﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Mvc.Ajax;
using System.Drawing;
using System.IO;
using System.Drawing.Imaging;
using System.Drawing.Drawing2D;

using Microsoft.Practices.Unity;

using ERPStore.Extensions;

using CloudSoft.Extensions;

namespace ERPStore.Web.Controllers
{
	public class MediaController : StoreController
	{
		public MediaController(
			ERPStore.Services.ICacheService cacheService
			, ERPStore.Services.IDocumentService documentService
			, EventBrokR.IPublisher eventPublisher
			) 
		{
			CacheService = cacheService;
			DocumentService = documentService;
			EventPublisher = eventPublisher;
		}

		public ERPStore.Services.ICacheService CacheService { get; private set; }
		public ERPStore.Services.IDocumentService DocumentService { get; private set; }
		public EventBrokR.IPublisher EventPublisher { get; private set; }

		public ActionResult Image(string externalDocumentId, int width, int height, string fileName)
		{
			string fullFileName = null;
			string mimeType = "image/png";

			if (IsSourceModified(Request, Response))
			{
				Response.StatusCode = 304;
				Response.StatusDescription = "Not Modified";
				return new EmptyResult();
			}

			if (string.IsNullOrEmpty(externalDocumentId))
			{
				Logger.Debug("Picture not found {0}", fileName);
				return ImageFileDoesNotExists(fileName);
			}

			string reason = null;
			fullFileName = DocumentService.GetFileName(externalDocumentId, width, height, fileName, out mimeType, out reason);

			if (fullFileName.IsNullOrTrimmedEmpty())
			{
				var referer = (Request.UrlReferrer != null) ? Request.UrlReferrer.ToString() : null;
				EventPublisher.PublishAsync<Events.ImageBrokenEvent>(new Events.ImageBrokenEvent()
				{
					DocumentId = externalDocumentId,
					FileName = fileName,
					Reason = reason,
					UrlSource = referer,
				});
				return ImageFileDoesNotExists(fileName);
			}

			var ext = System.IO.Path.GetExtension(fileName);
			if (ext != null)
			{
				ext = ext.TrimStart('.');
				var kv = ERPStore.Extensions.MimeExtensions.MIMETypeDictionary.FirstOrDefault(i => ext.Equals(i.Key, StringComparison.InvariantCultureIgnoreCase));
				if (kv.Key != null)
				{
					mimeType = kv.Value;
				}
			}

			Response.Cache.SetCacheability(HttpCacheability.Public);
			Response.Cache.SetLastModified(DateTime.Now.AddMinutes(-1));

			return this.File(fullFileName, mimeType);
		}

		public ActionResult Download(string externalDocumentId, string fileName)
		{
			if (string.IsNullOrEmpty(externalDocumentId))
			{
				return ImageFileDoesNotExists(fileName);
			}

			var doc = DocumentService.GetByCode(externalDocumentId);
			if (doc == null)
			{
				return ImageFileDoesNotExists(fileName);
			}

			var content = DocumentService.GetDocumentContentByCode(externalDocumentId);

			Response.AddHeader("content-disposition", string.Format("attachement; filename={0}", fileName));
			Response.Charset = string.Empty;
			Response.Cache.SetCacheability(HttpCacheability.NoCache);

			if (content != null)
			{
				string mimeType = doc.MimeType;
				if (mimeType.IsNullOrTrimmedEmpty())
				{
					mimeType = "image/gif";
				}
				return this.File(content, mimeType);
			}



			return Content(string.Empty, "text/plain");
		}

		public ActionResult DocumentDownload(string title, string key)
		{
			byte[] content = DocumentService.GetDocumentContentByKey(key);
			Response.AddHeader("content-disposition", string.Format("attachement; filename={0}.pdf", title));
			Response.Charset = "";
			Response.Cache.SetCacheability(HttpCacheability.NoCache);
			return this.File(content, "application/pdf");
		}

		public ActionResult ImageFileDoesNotExists(string fileName)
		{
			var missingProductImage = GlobalConfiguration.Configuration.Settings.Catalog.MissingProductImageVirtualPath;
			if (missingProductImage != null)
			{
				var fullFileName = HttpContext.Server.MapPath(missingProductImage);
				var ext = System.IO.Path.GetExtension(fullFileName);
				var mimeType = "image/png";
				if (ext != null
					&& ext.Length > 0)
				{
					mimeType = ERPStore.Extensions.MimeExtensions.MIMETypeDictionary.FirstOrDefault(i => i.Key.Equals(ext.Trim('.'), StringComparison.InvariantCultureIgnoreCase)).Value;
					if (mimeType == null)
					{
						mimeType = "image/png";
					}
				}

				Response.Cache.SetCacheability(HttpCacheability.Public);
				Response.Cache.SetExpires(DateTime.Now.AddDays(1));
				Response.Cache.SetLastModified(DateTime.Now);

				return this.File(fullFileName, mimeType);
			}

			Response.StatusCode = 404;
			return this.Content(string.Format("file {0} does not exist", fileName), "text/plain");
		}

		public ActionResult RoundedCorner(string cornerType, int radius, int thickness, string outsideColor, string insideColor, string curveColor)
		{
			byte[] result = null;
			using (var bmp = new Bitmap(radius, radius, PixelFormat.Format32bppArgb))
			{
				bmp.MakeTransparent();
				using (var g = Graphics.FromImage(bmp))
				{
					g.SmoothingMode = SmoothingMode.None;
					string outsideHTMLColor = "#" + outsideColor;
					string insideHTMLColor = "#" + insideColor;
					string curveHTMLColor = "#" + curveColor;

					g.Clear(ColorTranslator.FromHtml(outsideHTMLColor));
					Brush insideBrush = new SolidBrush(ColorTranslator.FromHtml(insideHTMLColor));
					Brush borderBrush = new SolidBrush(ColorTranslator.FromHtml(curveHTMLColor));
					Pen borderPen = new Pen(borderBrush, 1f);
					switch (cornerType.ToLower())
					{
						case "tl":
							g.FillEllipse(insideBrush, 0, 0, radius * 2, radius * 2);
							g.DrawEllipse(borderPen, 0, 0, radius * 2, radius * 2);
							break;

						case "tr":
							g.FillEllipse(insideBrush, -radius - 1, 0, radius * 2, radius * 2);
							g.DrawEllipse(borderPen, -radius - 1, 0, radius * 2, radius * 2);
							break;

						case "bl":
							g.FillEllipse(insideBrush, 0, (radius - (radius * 2)) - 1, radius * 2, radius * 2);
							g.DrawEllipse(borderPen, 0, (radius - (radius * 2)) - 1, radius * 2, radius * 2);
							break;

						case "br":
							g.FillEllipse(insideBrush, (int)(-radius - 1), (int)((radius - (radius * 2)) - 1), (int)(radius * 2), (int)(radius * 2));
							g.DrawEllipse(borderPen, (int)(-radius - 1), (int)((radius - (radius * 2)) - 1), (int)(radius * 2), (int)(radius * 2));
							break;

						default:
							g.FillRectangle(insideBrush, 0, 0, radius, radius - radius);
							break;
					}
					var ms = new MemoryStream();
					bmp.Save(ms, ImageFormat.Gif);
					result = ms.GetBuffer();
				}
			}
			Response.Cache.SetCacheability(HttpCacheability.Public);
			Response.Cache.SetExpires(DateTime.Now.AddDays(1));
			return this.File(result, "image/gif");
		}

		#region Partial Rendering

		public ActionResult ShowAttachmentList(ERPStore.Models.Product product, string viewName)
		{
			var list = DocumentService.GetMediaList(product);
			list.RemoveAll(i => i.MimeType == null 
								|| i.MimeType.StartsWith("image/")
								);
			ViewData.Model = list;
			return PartialView(viewName);
		}

		#endregion

		private static bool IsSourceModified(HttpRequestBase request, HttpResponseBase response)
		{
			bool dateModified = false;

			string requestIfModifiedSinceHeader = request.Headers["If-Modified-Since"] ?? string.Empty;
			DateTime requestIfModifiedSince = DateTime.MinValue;
			DateTime.TryParse(requestIfModifiedSinceHeader, out requestIfModifiedSince);

			if (requestIfModifiedSince.AddDays(1) > DateTime.Now)
			{
				dateModified = true;
			}
			else
			{
				dateModified = false;
			}

			return dateModified ;
		}
	}
}
